import urllib.parse
import copy
import json
import requests
from lxml import etree
from impl._bing_misc import parse_bing_image_custom_search_api

_parser = etree.HTMLParser()


class BingImageJsonAPICrawler:
    def __init__(self, search_word: str, thumbnail_only, request_session, headers, connection_timeout, verbose):
        headers = copy.copy(headers)
        query_name = urllib.parse.quote(search_word)
        base_search_url = f'https://cn.bing.com/images/search?q={query_name}&form=QBIR&first=1&tsc=ImageBasicHover'
        base_search_request = request_session.get(base_search_url, headers=headers['SITE_HEADER'], timeout=connection_timeout)
        base_search_request.raise_for_status()
        tree = etree.fromstring(base_search_request.content, parser=_parser)
        element = tree.find(".//a[@class='iusc']")
        assert element is not None
        link = element.get('href')
        assert link is not None and len(link) > 0
        detail_search_url = f'https://cn.bing.com{link}'
        detail_search_request = request_session.get(detail_search_url, headers=headers['SITE_HEADER'], timeout=connection_timeout)
        detail_search_request.raise_for_status()
        tree = etree.fromstring(detail_search_request.content, parser=_parser)
        element = tree.find(".//div[@id='b_content']//div[@id='b_idpdata']")
        assert element is not None
        persisted_query_string = element.get('data-pagec')
        persisted_query_string = json.loads(persisted_query_string)
        persisted_query_string = persisted_query_string['persistedQueryStrings']

        api_header = headers['API_HEADER']
        api_header['referer'] = detail_search_url

        self.persisted_query_string = persisted_query_string
        self.batch_size = 25
        self.offset = 0
        self.query_name = query_name
        self.request_session = request_session
        self.thumbnail_only = thumbnail_only
        self.headers = headers
        self.connection_timeout = connection_timeout
        self.verbose = verbose
        self.no_next = False

    def get_next(self):
        if self.no_next:
            return None
        api_url = f'https://cn.bing.com/images/api/custom/search?q={self.query_name}&count={self.batch_size}&offset={self.offset}&{self.persisted_query_string}'

        try:
            api_request = self.request_session.get(api_url, headers=self.headers['API_HEADER'], timeout=self.connection_timeout)
            api_request.raise_for_status()
            api_response = json.loads(api_request.content)
        except requests.RequestException as e:
            if self.verbose:
                print(f'{api_url}: {e}')
            return None

        has_next, next_offset, results = parse_bing_image_custom_search_api(api_response, self.headers, self.thumbnail_only)

        self.offset = next_offset
        if not has_next:
            self.no_next = True

        return results
